﻿/*
 * This file is part of CommunitySettlers.
 *
 * CommunitySettlers is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * CommunitySettlers is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with CommunitySettlers.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * Author: Christoph Husse
 * 
 * Also checkout our homepage: http://communitysettlers.codeplex.com/
 */
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Threading;

namespace SettlersEngine
{
    internal interface IVisualObjectFactory
    {
        IVisualObject CreateResource(RuntimeMap inParent, IResourceObject inResource);
        IVisualSizedObject CreateBuilding(RuntimeMap inParent, IBuildableObject inBuilding);
        IVisualObject CreateStatic(RuntimeMap inParent, IStaticObject inStatic);
        IVisualObject CreateMoveable(RuntimeMap inParent, IMovableObject inMovable);
    }

    internal partial class RuntimeMap
    {
        internal const Int32 FREE_DISTURBANCE = 4;
        internal const Int32 RESOURCE_TOPOLOGY_GRANULARITY = 10;

        public const Int32 MAX_RESOURCE_STACK = 8;
        public const Int64 CYCLE_MILLIS = 30;
        public const Double NORMAL_NODE_TIME = 1000;
        public const Double CYCLES_TO_GRIDPOS = 1.0 / (NORMAL_NODE_TIME / CYCLE_MILLIS);
        public const Double GRIDPOS_TO_CYCLES = 1.0 / CYCLES_TO_GRIDPOS;
        
        public Int32 Width { get; private set; }
        public Int32 Height { get; private set; }
        private System.Diagnostics.Stopwatch m_Watch = new System.Diagnostics.Stopwatch();
        private Object m_ChangeLock = new Object();
        public IVisualObjectFactory Factory { get; private set; }
        public AnimationTime AnimationTime { get; private set; }
        private Int64 m_InternalIDProvider = 0x7FFFFFFFFFFFFFFF;
        private Boolean m_HasBuildSpaceChanged = false;
        internal Exported.GameInstance Game { get; private set; }
        public event DNotifyHandler<RuntimeMap> OnBuildSpaceChanged;
        private DispatcherTimer m_ProcessTimer = new DispatcherTimer();
        public RuntimeGrid Grid { get; private set; }
        private Random m_Random = new Random();

        public RuntimeMap(
            Exported.GameInstance inGame,
            Int32 inWidth,
            Int32 inHeight,
            IVisualObjectFactory inFactory)
        {
            if ((inFactory == null) || (inGame == null))
                throw new ArgumentNullException();

            ScreenWidth = 60;
            ScreenHeight = 60;
            Game = inGame;
            m_Watch.Start();
            Width = inWidth;
            Height = inHeight;
            Factory = inFactory;
            Grid = new RuntimeGrid(this, Width, Height);

            InitConfig();

            AnimationTime = new AnimationTime(m_Watch.Elapsed);
            m_ProcessTimer.Interval = TimeSpan.FromMilliseconds(30);
            m_ProcessTimer.Tick += Process;
            m_ProcessTimer.Start();
        }

        internal void RaiseBuildSpaceChange()
        {
            m_HasBuildSpaceChanged = true;
        }

        public Int64 AcquireInternalID()
        {
            return System.Threading.Interlocked.Increment(ref m_InternalIDProvider);
        }
    }
}
